Link to this headingBash Programing

Bash variables and command substitution

Scripting in bash
Learn to make bash scripts
Check your Bash Scripts
Pure Bash Bible

Script:

#!/usr/bin/env bash #Set Exit on Error set -o errexit #Set Error on unset Variables set -o nounset #Set Error on a Piped Command notworking set -o pipefail #Set Debugging when executed like `TRACE=1 ./script.sh` if [[ "${TRACE-0}" == "1" ]]; then set -o xtrace; fi #Use [[ ]] for if and while if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then echo 'Usage: ./script.sh arg-one arg-two This is an awesome bash script to make your life better.' exit fi cd "$(dirname "$0")" main() { echo do awesome stuff } main "$@"

Link to this headingStrings

Link to this headingTrim leading and trailing white-space from string

This is an alternative to sed, awk, perl and other tools. The function below works by finding all leading and trailing white-space and removing it from the start and end of the string. The : built-in is used in place of a temporary variable.

Example Function:

trim_string() { # Usage: trim_string " example string " : "${1#"${1%%[![:space:]]*}"}" : "${_%"${_##*[![:space:]]}"}" printf '%s\n' "$_" }

Example Usage:

$ trim_string " Hello, World " Hello, World $ name=" John Black " $ trim_string "$name" John Black

Link to this headingTrim all white-space from string and truncate spaces

This is an alternative to sed, awk, perl and other tools. The function below works by abusing word splitting to create a new string without leading/trailing white-space and with truncated spaces.

Example Function:

# shellcheck disable=SC2086,SC2048 trim_all() { # Usage: trim_all " example string " set -f set -- $* printf '%s\n' "$*" set +f }

Example Usage:

$ trim_all " Hello, World " Hello, World $ name=" John Black is my name. " $ trim_all "$name" John Black is my name.

Link to this headingUse regex on a string

The result of bash’s regex matching can be used to replace sed for a large number of use-cases.

CAVEAT: This example only prints the first matching group. When using multiple capture groups some modification is needed.

Example Function:

regex() { # Usage: regex "string" "regex" [[ $1 =~ $2 ]] && printf '%s\n' "${BASH_REMATCH[1]}" }

Example Usage:

$ # Trim leading white-space. $ regex ' hello' '^\s*(.*)' hello $ # Validate a hex color. $ regex "#FFFFFF" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$' #FFFFFF $ # Validate a hex color (invalid). $ regex "red" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$' # no output (invalid)

Example Usage in script:

is_hex_color() { if [[ $1 =~ ^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$ ]]; then printf '%s\n' "${BASH_REMATCH[1]}" else printf '%s\n' "error: $1 is an invalid color." return 1 fi } read -r color is_hex_color "$color" || color="#FFFFFF" # Do stuff.

Link to this headingSplit a string on a delimiter

This is an alternative to cut, awk and other tools.

Example Function:

split() { # Usage: split "string" "delimiter" IFS=$'\n' read -d "" -ra arr <<< "${1//$2/$'\n'}" printf '%s\n' "${arr[@]}" }

Example Usage:

$ split "apples,oranges,pears,grapes" "," apples oranges pears grapes $ split "1, 2, 3, 4, 5" ", " 1 2 3 4 5 # Multi char delimiters work too! $ split "hello---world---my---name---is---john" "---" hello world my name is john

Link to this headingChange a string to lowercase

Example Function:

lower() { # Usage: lower "string" printf '%s\n' "${1,,}" }

Example Usage:

$ lower "HELLO" hello $ lower "HeLlO" hello $ lower "hello" hello

Link to this headingChange a string to uppercase

Example Function:

upper() { # Usage: upper "string" printf '%s\n' "${1^^}" }

Example Usage:

$ upper "hello" HELLO $ upper "HeLlO" HELLO $ upper "HELLO" HELLO

Link to this headingReverse a string case

Example Function:

reverse_case() { # Usage: reverse_case "string" printf '%s\n' "${1~~}" }

Example Usage:

$ reverse_case "hello" HELLO $ reverse_case "HeLlO" hElLo $ reverse_case "HELLO" hello

Link to this headingTrim quotes from a string

Example Function:

trim_quotes() { # Usage: trim_quotes "string" : "${1//\'}" printf '%s\n' "${_//\"}" }

Example Usage:

$ var="'Hello', \"World\"" $ trim_quotes "$var" Hello, World

Link to this headingStrip all instances of pattern from string

Example Function:

strip_all() { # Usage: strip_all "string" "pattern" printf '%s\n' "${1//$2}" }

Example Usage:

$ strip_all "The Quick Brown Fox" "[aeiou]" Th Qck Brwn Fx $ strip_all "The Quick Brown Fox" "[[:space:]]" TheQuickBrownFox $ strip_all "The Quick Brown Fox" "Quick " The Brown Fox

Link to this headingStrip first occurrence of pattern from string

Example Function:

strip() { # Usage: strip "string" "pattern" printf '%s\n' "${1/$2}" }

Example Usage:

$ strip "The Quick Brown Fox" "[aeiou]" Th Quick Brown Fox $ strip "The Quick Brown Fox" "[[:space:]]" TheQuick Brown Fox

Link to this headingStrip pattern from start of string

Example Function:

lstrip() { # Usage: lstrip "string" "pattern" printf '%s\n' "${1##$2}" }

Example Usage:

$ lstrip "The Quick Brown Fox" "The " Quick Brown Fox

Link to this headingStrip pattern from end of string

Example Function:

rstrip() { # Usage: rstrip "string" "pattern" printf '%s\n' "${1%%$2}" }

Example Usage:

$ rstrip "The Quick Brown Fox" " Fox" The Quick Brown

Link to this headingPercent-encode a string

Example Function:

urlencode() { # Usage: urlencode "string" local LC_ALL=C for (( i = 0; i < ${#1}; i++ )); do : "${1:i:1}" case "$_" in [a-zA-Z0-9.~_-]) printf '%s' "$_" ;; *) printf '%%%02X' "'$_" ;; esac done printf '\n' }

Example Usage:

$ urlencode "https://github.com/dylanaraps/pure-bash-bible" https%3A%2F%2Fgithub.com%2Fdylanaraps%2Fpure-bash-bible

Link to this headingDecode a percent-encoded string

Example Function:

urldecode() { # Usage: urldecode "string" : "${1//+/ }" printf '%b\n' "${_//%/\\x}" }

Example Usage:

$ urldecode "https%3A%2F%2Fgithub.com%2Fdylanaraps%2Fpure-bash-bible" https://github.com/dylanaraps/pure-bash-bible

Link to this headingCheck if string contains a sub-string

Using a test:

if [[ $var == *sub_string* ]]; then printf '%s\n' "sub_string is in var." fi # Inverse (substring not in string). if [[ $var != *sub_string* ]]; then printf '%s\n' "sub_string is not in var." fi # This works for arrays too! if [[ ${arr[*]} == *sub_string* ]]; then printf '%s\n' "sub_string is in array." fi

Using a case statement:

case "$var" in *sub_string*) # Do stuff ;; *sub_string2*) # Do more stuff ;; *) # Else ;; esac

Link to this headingCheck if string starts with sub-string

if [[ $var == sub_string* ]]; then printf '%s\n' "var starts with sub_string." fi # Inverse (var does not start with sub_string). if [[ $var != sub_string* ]]; then printf '%s\n' "var does not start with sub_string." fi

Link to this headingCheck if string ends with sub-string

if [[ $var == *sub_string ]]; then printf '%s\n' "var ends with sub_string." fi # Inverse (var does not end with sub_string). if [[ $var != *sub_string ]]; then printf '%s\n' "var does not end with sub_string." fi

Link to this headingLength of string

var="some string" echo ${#var} # 11

Link to this headingArrays

Link to this headingReverse an array

Enabling extdebug allows access to the BASH_ARGV array which stores the current function’s arguments in reverse.

Example Function:

reverse_array() { # Usage: reverse_array "array" shopt -s extdebug f()(printf '%s\n' "${BASH_ARGV[@]}"); f "$@" shopt -u extdebug }

Example Usage:

$ reverse_array 1 2 3 4 5 5 4 3 2 1 $ arr=(red blue green) $ reverse_array "${arr[@]}" green blue red

Link to this headingRemove duplicate array elements

Create a temporary associative array. When setting associative array values and a duplicate assignment occurs, bash overwrites the key. This allows us to effectively remove array duplicates.

Example Function:

remove_array_dups() { # Usage: remove_array_dups "array" declare -A tmp_array for i in "$@"; do [[ $i ]] && IFS=" " tmp_array["${i:- }"]=1 done printf '%s\n' "${!tmp_array[@]}" }

Example Usage:

$ remove_array_dups 1 1 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5 5 1 2 3 4 5 $ arr=(red red green blue blue) $ remove_array_dups "${arr[@]}" red green blue

Link to this headingRandom array element

Example Function:

random_array_element() { # Usage: random_array_element "array" local arr=("$@") printf '%s\n' "${arr[RANDOM % $#]}" }

Example Usage:

$ array=(red green blue yellow brown) $ random_array_element "${array[@]}" yellow # Multiple arguments can also be passed. $ random_array_element 1 2 3 4 5 6 7 3

Link to this headingCycle through an array

Each time the printf is called, the next array element is printed. When the print hits the last array element it starts from the first element again.

arr=(a b c d) cycle() { printf '%s ' "${arr[${i:=0}]}" ((i=i>=${#arr[@]}-1?0:++i)) }

Link to this headingToggle between two values

This works the same as above, this is just a different use case.

arr=(true false) cycle() { printf '%s ' "${arr[${i:=0}]}" ((i=i>=${#arr[@]}-1?0:++i)) }

Link to this headingLoops

Link to this headingLoop over a range of numbers

Alternative to seq.

# Loop from 0-100 (no variable support). for i in {0..100}; do printf '%s\n' "$i" done

Link to this headingLoop over a variable range of numbers

Alternative to seq.

# Loop from 0-VAR. VAR=50 for ((i=0;i<=VAR;i++)); do printf '%s\n' "$i" done

Link to this headingLoop over an array

arr=(apples oranges tomatoes) # Just elements. for element in "${arr[@]}"; do printf '%s\n' "$element" done

Link to this headingLoop over an array with an index

arr=(apples oranges tomatoes) # Elements and index. for i in "${!arr[@]}"; do printf '%s\n' "${arr[i]}" done # Alternative method. for ((i=0;i<${#arr[@]};i++)); do printf '%s\n' "${arr[i]}" done

Link to this headingLoop over the contents of a file

while read -r line; do printf '%s\n' "$line" done < "file"

Link to this headingLoop over files and directories

Don’t use ls.

# Greedy example. for file in *; do printf '%s\n' "$file" done # PNG files in dir. for file in ~/Pictures/*.png; do printf '%s\n' "$file" done # Iterate over directories. for dir in ~/Downloads/*/; do printf '%s\n' "$dir" done # Brace Expansion. for file in /path/to/parentdir/{file1,file2,subdir/file3}; do printf '%s\n' "$file" done # Iterate recursively. shopt -s globstar for file in ~/Pictures/**/*; do printf '%s\n' "$file" done shopt -u globstar

Link to this headingFile Handling

Link to this headingRead a file to a string

Alternative to the cat command.

file_data="$(<"file")"

Read a file to an array (by line)

Alternative to the cat command.

# Bash <4 IFS=$'\n' read -d "" -ra file_data < "file" # Bash 4+ mapfile -t file_data < "file"

Link to this headingGet the first N lines of a file

Alternative to the head command.

Example Function:

head() { # Usage: head "n" "file" mapfile -tn "$1" line < "$2" printf '%s\n' "${line[@]}" }

Example Usage:

$ head 2 ~/.bashrc # Prompt PS1='' $ head 1 ~/.bashrc # Prompt

Link to this headingGet the last N lines of a file

Alternative to the tail command.

Example Function:

tail() { # Usage: tail "n" "file" mapfile -tn 0 line < "$2" printf '%s\n' "${line[@]: -$1}" }

Example Usage:

$ tail 2 ~/.bashrc # Enable tmux. # [[ -z "$TMUX" ]] && exec tmux $ tail 1 ~/.bashrc # [[ -z "$TMUX" ]] && exec tmux

Link to this headingGet the number of lines in a file

Alternative to wc -l.

Example Function (bash 4.x):

lines() { # Usage: lines "file" mapfile -tn 0 lines < "$1" printf '%s\n' "${#lines[@]}" }

Example Function (bash 3.x):

This method uses less memory than the mapfile method and works in bash 3 but it is slower for bigger files.

lines_loop() { # Usage: lines_loop "file" count=0 while IFS= read -r _; do ((count++)) done < "$1" printf '%s\n' "$count" }

Example Usage:

$ lines ~/.bashrc 48 $ lines_loop ~/.bashrc 48

Link to this headingCount files or directories in directory

This works by passing the output of the glob to the function and then counting the number of arguments.

Example Function:

count() { # Usage: count /path/to/dir/* # count /path/to/dir/*/ printf '%s\n' "$#" }

Example Usage:

# Count all files in dir. $ count ~/Downloads/* 232 # Count all dirs in dir. $ count ~/Downloads/*/ 45 # Count all jpg files in dir. $ count ~/Pictures/*.jpg 64

Link to this headingCreate an empty file

Alternative to touch.

# Shortest. >file # Longer alternatives: :>file echo -n >file printf '' >file

Link to this headingExtract lines between two markers

Example Function:

extract() { # Usage: extract file "opening marker" "closing marker" while IFS=$'\n' read -r line; do [[ $extract && $line != "$3" ]] && printf '%s\n' "$line" [[ $line == "$2" ]] && extract=1 [[ $line == "$3" ]] && extract= done < "$1" }

Example Usage:

# Extract code blocks from MarkDown file. $ extract ~/projects/pure-bash/README.md '```sh' '```' # Output here...

Link to this headingFile Paths

Link to this headingGet the directory name of a file path

Alternative to the dirname command.

Example Function:

dirname() { # Usage: dirname "path" printf '%s\n' "${1%/*}/" }

Example Usage:

$ dirname ~/Pictures/Wallpapers/1.jpg /home/black/Pictures/Wallpapers/ $ dirname ~/Pictures/Downloads/ /home/black/Pictures/

Link to this headingGet the base-name of a file path

Alternative to the basename command.

Example Function:

basename() { # Usage: basename "path" : "${1%/}" printf '%s\n' "${_##*/}" }

Example Usage:

$ basename ~/Pictures/Wallpapers/1.jpg 1.jpg $ basename ~/Pictures/Downloads/ Downloads

Link to this headingVariables

Link to this headingAssign and access a variable using a variable

$ hello_world="value" # Create the variable name. $ var="world" $ ref="hello_$var" # Print the value of the variable name stored in 'hello_$var'. $ printf '%s\n' "${!ref}" value

Alternatively, on bash 4.3+:

$ hello_world="value" $ var="world" # Declare a nameref. $ declare -n ref=hello_$var $ printf '%s\n' "$ref" value

Link to this headingName a variable based on another variable

$ var="world" $ declare "hello_$var=value" $ printf '%s\n' "$hello_world" value

Link to this headingEscape Sequences

Link to this headingText Colors

SequenceWhat does it do?Value
e[38;5;<NUM>mSet text foreground color.0-255
e[48;5;<NUM>mSet text background color.0-255
e[38;2;<R>;<G>;<B>mSet text foreground color to RGB color.R, G, B
e[48;2;<R>;<G>;<B>mSet text background color to RGB color.R, G, B

Link to this headingText Attributes

SequenceWhat does it do?
e[mReset text formatting and colors.
e[1mBold text.
e[2mFaint text.
e[3mItalic text.
e[4mUnderline text.
e[5mSlow blink.
e[7mSwap foreground and background colors.

Link to this headingCursor Movement

SequenceWhat does it do?Value
e[<LINE>;<COLUMN>HMove cursor to absolute position.line, column
e[HMove cursor to home position (0,0).
e[<NUM>AMove cursor up N lines.num
e[<NUM>BMove cursor down N lines.num
e[<NUM>CMove cursor right N columns.num
e[<NUM>DMove cursor left N columns.num
e[sSave cursor position.
e[uRestore cursor position.

Link to this headingErasing Text

SequenceWhat does it do?
e[KErase from cursor position to end of line.
e[1KErase from cursor position to start of line.
e[2KErase the entire current line.
e[JErase from the current line to the bottom of the screen.
e[1JErase from the current line to the top of the screen.
e[2JClear the screen.
e[2Je[HClear the screen and move cursor to 0,0.

Link to this headingParameter Extension

Link to this headingIndirection



${!VAR}Access a variable based on the value of VAR
${!VAR*}Expand to IFS separated list of variable names starting with VAR
${!VAR@}Expand to IFS separated list of variable names starting with VAR. If double-quoted, each variable name expands to a separate word.

Link to this headingReplacement

ParameterWhat does it do?
${VAR#PATTERN}Remove shortest match of pattern from start of string.
${VAR##PATTERN}Remove longest match of pattern from start of string.
${VAR%PATTERN}Remove shortest match of pattern from end of string.
${VAR%%PATTERN}Remove longest match of pattern from end of string.
${VAR/PATTERN/REPLACE}Replace first match with string.
${VAR//PATTERN/REPLACE}Replace all matches with string.
${VAR/PATTERN}Remove first match.
${VAR//PATTERN}Remove all matches.

Link to this headingLength

ParameterWhat does it do?
${#VAR}Length of var in characters.
${#ARR[@]}Length of array in elements.

Link to this headingExpansion



${VAR:OFFSET}Remove first N chars from variable.
${VAR:OFFSET:LENGTH}Get substring from N character to N character. (${VAR:10:10}: Get sub-string from char 10 to char 20)
${VAR:: OFFSET}Get first N chars from variable.
${VAR:: -OFFSET}Remove last N chars from variable.
${VAR: -OFFSET}Get last N chars from variable.
${VAR:OFFSET:-OFFSET}Cut first N chars and last N chars.

Link to this headingCase Modification

ParameterWhat does it do?
${VAR^}Uppercase first character.
${VAR^^}Uppercase all characters.
${VAR,}Lowercase first character.
${VAR,,}Lowercase all characters.
${VAR~}Reverse case of first character.
${VAR~~}Reverse case of all characters.

Link to this headingDefault Value

ParameterWhat does it do?
${VAR:-STRING}If VAR is empty or unset, use STRING as its value.
${VAR-STRING}If VAR is unset, use STRING as its value.
${VAR:=STRING}If VAR is empty or unset, set the value of VAR to STRING.
${VAR=STRING}If VAR is unset, set the value of VAR to STRING.
${VAR:+STRING}If VAR is not empty, use STRING as its value.
${VAR+STRING}If VAR is set, use STRING as its value.
${VAR:?STRING}Display an error if empty or unset.
${VAR?STRING}Display an error if unset.

Link to this headingBrace Expansion

Link to this headingRanges

# Syntax: {<START>..<END>} # Print numbers 1-100. echo {1..100} # Print range of floats. echo 1.{1..9} # Print chars a-z. echo {a..z} echo {A..Z} # Nesting. echo {A..Z}{0..9} # Print zero-padded numbers. # CAVEAT: bash 4+ echo {01..100} # Change increment amount. # Syntax: {<START>..<END>..<INCREMENT>} # CAVEAT: bash 4+ echo {1..10..2} # Increment by 2.

Link to this headingString Lists

echo {apples,oranges,pears,grapes} # Example Usage: # Remove dirs Movies, Music and ISOS from ~/Downloads/. rm -rf ~/Downloads/{Movies,Music,ISOS}

Link to this headingConditional Expressions

Link to this headingFile Conditionals

ExpressionValueWhat does it do?
-afileIf file exists.
-bfileIf file exists and is a block special file.
-cfileIf file exists and is a character special file.
-dfileIf file exists and is a directory.
-efileIf file exists.
-ffileIf file exists and is a regular file.
-gfileIf file exists and its set-group-id bit is set.
-hfileIf file exists and is a symbolic link.
-kfileIf file exists and its sticky-bit is set
-pfileIf file exists and is a named pipe (FIFO).
-rfileIf file exists and is readable.
-sfileIf file exists and its size is greater than zero.
-tfdIf file descriptor is open and refers to a terminal.
-ufileIf file exists and its set-user-id bit is set.
-wfileIf file exists and is writable.
-xfileIf file exists and is executable.
-GfileIf file exists and is owned by the effective group ID.
-LfileIf file exists and is a symbolic link.
-NfileIf file exists and has been modified since last read.
-OfileIf file exists and is owned by the effective user ID.
-SfileIf file exists and is a socket.

Link to this headingFile Comparisons



file -ef file2If both files refer to the same inode and device numbers.
file -nt file2If file is newer than file2 (uses modification time) or file exists and file2 does not.
file -ot file2If file is older than file2 (uses modification time) or file2 exists and file does not.

Link to this headingVariable Conditionals

ExpressionValueWhat does it do?
-ooptIf shell option is enabled.
-vvarIf variable has a value assigned.
-RvarIf variable is a name reference.
-zvarIf the length of string is zero.
-nvarIf the length of string is non-zero.

Link to this headingVariable Comparisons

ExpressionWhat does it do?
var = var2Equal to.
var == var2Equal to (synonym for =).
var != var2Not equal to.
var < var2Less than (in ASCII alphabetical order.)
var > var2Greater than (in ASCII alphabetical order.)

Link to this headingArithmetic Operators

Link to this headingAssignment

OperatorsWhat does it do?
=Initialize or change the value of a variable.

Link to this headingArithmetic

OperatorsWhat does it do?
*Multiplication
**Exponentiation
+=Plus-Equal (Increment a variable.)
-=Minus-Equal (Decrement a variable.)
*=Times-Equal (Multiply a variable.)
/=Slash-Equal (Divide a variable.)
%=Mod-Equal (Remainder of dividing a variable.)

Link to this headingBitwise

OperatorsWhat does it do?
<<Bitwise Left Shift
<<=Left-Shift-Equal
>>Bitwise Right Shift
>>=Right-Shift-Equal
&Bitwise AND
&=Bitwise AND-Equal
|Bitwise OR
|=Bitwise OR-Equal
~Bitwise NOT
^Bitwise XOR
^=Bitwise XOR-Equal

Link to this headingLogical

OperatorsWhat does it do?

Link to this headingMiscellaneous

OperatorsWhat does it do?Example
,Comma Separator((a=1,b=2,c=3))

Link to this headingArithmetic

Link to this headingSimpler syntax to set variables

# Simple math ((var=1+2)) # Decrement/Increment variable ((var++)) ((var--)) ((var+=1)) ((var-=1)) # Using variables ((var=var2*arr[2]))

Link to this headingTernary Tests

# Set the value of var to var2 if var2 is greater than var. # var: variable to set. # var2>var: Condition to test. # ?var2: If the test succeeds. # :var: If the test fails. ((var=var2>var?var2:var))

Link to this headingTraps

Traps allow a script to execute code on various signals. In pxltrm (a pixel art editor written in bash) traps are used to redraw the user interface on window resize. Another use case is cleaning up temporary files on script exit.

Traps should be added near the start of scripts so any early errors are also caught.

Link to this headingDo something on script exit

# Clear screen on script exit. trap 'printf \\e[2J\\e[H\\e[m' EXIT

Link to this headingIgnore terminal interrupt (CTRL+C, SIGINT)

trap '' INT

Link to this headingReact to window resize

# Call a function on window resize. trap 'code_here' SIGWINCH

Link to this headingDo something before every command

trap 'code_here' DEBUG

Link to this headingDo something when a shell function or a sourced file finishes executing

trap 'code_here' RETURN

Link to this headingPerformance

Link to this headingDisable Unicode

If unicode is not required, it can be disabled for a performance increase. Results may vary however there have been noticeable improvements in neofetch and other programs.

# Disable unicode. LC_ALL=C LANG=C

Link to this headingObsolete Syntax

Link to this headingShebang

Use #!/usr/bin/env bash instead of #!/bin/bash.

  • The former searches the user’s PATH to find the bash binary.
  • The latter assumes it is always installed to /bin/ which can cause issues.

Link to this headingCommand Substitution

Use $() instead of ` `.

# Right. var="$(command)" # Wrong. var=`command` # $() can easily be nested whereas `` cannot. var="$(command "$(command)")"

Link to this headingFunction Declaration

Do not use the function keyword, it reduces compatibility with older versions of bash.

# Right. do_something() { # ... } # Wrong. function do_something() { # ... }

Link to this headingInternal Varables

Get the location to the bash binary

"$BASH"

Get the version of the current running bash process

# As a string. "$BASH_VERSION" # As an array. "${BASH_VERSINFO[@]}"

Link to this headingOpen the user’s preferred text editor

"$EDITOR" "$file" # NOTE: This variable may be empty, set a fallback value. "${EDITOR:-vi}" "$file"

Link to this headingGet the name of the current function

# Current function. "${FUNCNAME[0]}" # Parent function. "${FUNCNAME[1]}" # So on and so forth. "${FUNCNAME[2]}" "${FUNCNAME[3]}" # All functions including parents. "${FUNCNAME[@]}"

Link to this headingGet the host-name of the system

"$HOSTNAME" # NOTE: This variable may be empty. # Optionally set a fallback to the hostname command. "${HOSTNAME:-$(hostname)}"

Link to this headingGet the architecture of the Operating System

"$HOSTTYPE"

Link to this headingGet the name of the Operating System / Kernel

This can be used to add conditional support for different Operating Systems without needing to call uname.

"$OSTYPE"

Link to this headingGet the current working directory

This is an alternative to the pwd built-in.

"$PWD"

Link to this headingGet the number of seconds the script has been running

"$SECONDS"

Link to this headingGet a pseudorandom integer

Each time $RANDOM is used, a different integer between 0 and 32767 is returned. This variable should not be used for anything related to security (this includes encryption keys etc).

"$RANDOM"

Link to this headingInformation about the terminal

Get the terminal size in lines and columns (from a script)

This is handy when writing scripts in pure bash and stty/tput can’t be
called.

Example Function:

get_term_size() { # Usage: get_term_size # (:;:) is a micro sleep to ensure the variables are # exported immediately. shopt -s checkwinsize; (:;:) printf '%s\n' "$LINES $COLUMNS" }

Example Usage:

# Output: LINES COLUMNS $ get_term_size 15 55

Link to this headingGet the terminal size in pixels

CAVEAT: This does not work in some terminal emulators.

Example Function:

get_window_size() { # Usage: get_window_size printf '%b' "${TMUX:+\\ePtmux;\\e}\\e[14t${TMUX:+\\e\\\\}" IFS=';t' read -d t -t 0.05 -sra term_size printf '%s\n' "${term_size[1]}x${term_size[2]}" }

Example Usage:

# Output: WIDTHxHEIGHT $ get_window_size 1200x800 # Output (fail): $ get_window_size x

Link to this headingGet the current cursor position

This is useful when creating a TUI in pure bash.

Example Function:

get_cursor_pos() { # Usage: get_cursor_pos IFS='[;' read -p $'\e[6n' -d R -rs _ y x _ printf '%s\n' "$x $y" }

Example Usage:

# Output: X Y $ get_cursor_pos 1 8

Link to this headingConversion

Link to this headingConvert a hex color to RGB

Example Function:

hex_to_rgb() { # Usage: hex_to_rgb "#FFFFFF" # hex_to_rgb "000000" : "${1/\#}" ((r=16#${_:0:2},g=16#${_:2:2},b=16#${_:4:2})) printf '%s\n' "$r $g $b" }

Example Usage:

$ hex_to_rgb "#FFFFFF" 255 255 255

Link to this headingConvert an RGB color to hex

Example Function:

rgb_to_hex() { # Usage: rgb_to_hex "r" "g" "b" printf '#%02x%02x%02x\n' "$1" "$2" "$3" }

Example Usage:

$ rgb_to_hex "255" "255" "255" #FFFFFF

Link to this headingCode Golf

Shorter for loop syntax

# Tiny C Style. for((;i++<10;)){ echo "$i";} # Undocumented method. for i in {1..10};{ echo "$i";} # Expansion. for i in {1..10}; do echo "$i"; done # C Style. for((i=0;i<=10;i++)); do echo "$i"; done

Link to this headingShorter infinite loops

# Normal method while :; do echo hi; done # Shorter for((;;)){ echo hi;}

Link to this headingShorter function declaration

# Normal method f(){ echo hi;} # Using a subshell f()(echo hi) # Using arithmetic # This can be used to assign integer values. # Example: f a=1 # f a++ f()(($1)) # Using tests, loops etc. # NOTE: ‘while’, ‘until’, ‘case’, ‘(())’, ‘[[]]’ can also be used. f()if true; then echo "$1"; fi f()for i in "$@"; do echo "$i"; done

Shorter if syntax

# One line # Note: The 3rd statement may run when the 1st is true [[ $var == hello ]] && echo hi || echo bye [[ $var == hello ]] && { echo hi; echo there; } || echo bye # Multi line (no else, single statement) # Note: The exit status may not be the same as with an if statement [[ $var == hello ]] && echo hi # Multi line (no else) [[ $var == hello ]] && { echo hi # ... }

Simpler case statement to set variable

The : built-in can be used to avoid repeating variable= in a case statement. The $_ variable stores the last argument of the last command. : always succeeds so it can be used to store the variable value.

# Modified snippet from Neofetch. case "$OSTYPE" in "darwin"*) : "MacOS" ;; "linux"*) : "Linux" ;; *"bsd"* | "dragonfly" | "bitrig") : "BSD" ;; "cygwin" | "msys" | "win32") : "Windows" ;; *) printf '%s\n' "Unknown OS detected, aborting..." >&2 exit 1 ;; esac # Finally, set the variable. os="$_"

Link to this headingOthers

Use read as an alternative to the sleep command

Surprisingly, sleep is an external command and not a bash built-in.

CAVEAT: Requires bash 4+

Example Function:

read_sleep() { # Usage: sleep 1 # sleep 0.2 read -rt "$1" <> <(:) || : }

Example Usage:

read_sleep 1 read_sleep 0.1 read_sleep 30

For performance-critical situations, where it is not economic to open and close an excessive number of file descriptors, the allocation of a file descriptor may be done only once for all invocations of read:

(See the generic original implementation at https://blog.dhampir.no/content/sleeping-without-a-subprocess-in-bash-and-how-to-sleep-forever)

exec {sleep_fd}<> <(:) while some_quick_test; do # equivalent of sleep 0.001 read -t 0.001 -u $sleep_fd done

Link to this headingCheck if a program is in the user’s PATH

# There are 3 ways to do this and either one can be used. type -p executable_name &>/dev/null hash executable_name &>/dev/null command -v executable_name &>/dev/null # As a test. if type -p executable_name &>/dev/null; then # Program is in PATH. fi # Inverse. if ! type -p executable_name &>/dev/null; then # Program is not in PATH. fi # Example (Exit early if program is not installed). if ! type -p convert &>/dev/null; then printf '%s\n' "error: convert is not installed, exiting..." exit 1 fi

Get the current date using strftime

Bash’s printf has a built-in method of getting the date which can be used in place of the date command.

CAVEAT: Requires bash 4+

Example Function:

date() { # Usage: date "format" # See: 'man strftime' for format. printf "%($1)T\\n" "-1" }

Example Usage:

# Using above function. $ date "%a %d %b - %l:%M %p" Fri 15 Jun - 10:00 AM # Using printf directly. $ printf '%(%a %d %b - %l:%M %p)T\n' "-1" Fri 15 Jun - 10:00 AM # Assigning a variable using printf. $ printf -v date '%(%a %d %b - %l:%M %p)T\n' '-1' $ printf '%s\n' "$date" Fri 15 Jun - 10:00 AM

Link to this headingGet the username of the current user

CAVEAT: Requires bash 4.4+

$ : \\u # Expand the parameter as if it were a prompt string. $ printf '%s\n' "${_@P}" black

Link to this headingGenerate a UUID V4

CAVEAT: The generated value is not cryptographically secure.

Example Function:

uuid() { # Usage: uuid C="89ab" for ((N=0;N<16;++N)); do B="$((RANDOM%256))" case "$N" in 6) printf '4%x' "$((B%16))" ;; 8) printf '%c%x' "${C:$RANDOM%${#C}:1}" "$((B%16))" ;; 3|5|7|9) printf '%02x-' "$B" ;; *) printf '%02x' "$B" ;; esac done printf '\n' }

Example Usage:

$ uuid d5b6c731-1310-4c24-9fe3-55d556d44374

Link to this headingProgress bars

This is a simple way of drawing progress bars without needing a for loop
in the function itself.

Example Function:

bar() { # Usage: bar 1 10 # ^----- Elapsed Percentage (0-100). # ^-- Total length in chars. ((elapsed=$1*$2/100)) # Create the bar with spaces. printf -v prog "%${elapsed}s" printf -v total "%$(($2-elapsed))s" printf '%s\r' "[${prog// /-}${total}]" }

Example Usage:

for ((i=0;i<=100;i++)); do # Pure bash micro sleeps (for the example). (:;:) && (:;:) && (:;:) && (:;:) && (:;:) # Print the bar. bar "$i" "10" done printf '\n'

Link to this headingGet the list of functions in a script

get_functions() { # Usage: get_functions IFS=$'\n' read -d "" -ra functions < <(declare -F) printf '%s\n' "${functions[@]//declare -f }" }

Link to this headingBypass shell aliases

# alias ls # command # shellcheck disable=SC1001 \ls

Link to this headingBypass shell functions

# function ls # command command ls

Link to this headingRun a command in the background

This will run the given command and keep it running, even after the terminal or SSH connection is terminated. All output is ignored.

bkr() { (nohup "$@" &>/dev/null &) } bkr ./some_script.sh # some_script.sh is now running in the background

Link to this headingTemp cd in to folder

pushd / popd

for d1 in $(ls -d */) do # Store original working directory. original_wd="$(pwd)" cd "$d1" for d2 in $(ls -d */) do pushd "$d2" # Do something popd done # Return to original working directory cd "${original_wd}" done

Link to this headingArguments

Link to this headingEnvironment Variables

$0 :name of shell or shell script. $1, $2, $3, ... :positional parameters. $# :number of positional parameters. $? :most recent foreground pipeline exit status. $- :current options set for the shell. $$ :pid of the current shell (not subshell). $! :is the PID of the most recent background command. $DESKTOP_SESSION current display manager $EDITOR preferred text editor. $LANG current language. $PATH list of directories to search for executable files (i.e. ready-to-run programs) $PWD current directory $SHELL current shell $USER current username $HOSTNAME current hostname

Link to this headingSetting Default Arguments in Bash

#!/bin/bash FIRST_ARG="${1:-no_first_arg}" SECOND_ARG="${2:-no_second_arg}" THIRD_ARG="${3:-no_third_arg}" echo ${FIRST_ARG} echo ${SECOND_ARG} echo ${THIRD_ARG}

Timeout in scripts

#!/bin/bash TMOUT=5 echo You have 5 seconds to respond... read echo ${REPLY:-noreply}

Link to this headingBash File Testing

FlagDescription
-b filenameBlock special file
-c filenameSpecial character file
-d directorynameCheck for directory existence
-e filenameCheck for file existence
-f filenameCheck for regular file existence not a directory
-G filenameCheck if file exists and is owned by effective group ID.
-g filenametrue if file exists and is set-group-id.
-k filenameSticky bit
-L filenameSymbolic link
-O filenameTrue if file exists and is owned by the effective user id.
-r filenameCheck if file is a readable
-S filenameCheck if file is socket
-s filenameCheck if file is nonzero size
-u filenameCheck if file set-ser-id bit is set
-w filenameCheck if file is writable
-x filenameCheck if file is executable

Check if file exists:

#!/bin/bash file="./file" if [ -f $file ]; then echo "File exists" else echo "File does not exists" fi

Link to this headingCheck for line in file before adding

if ! grep -qF "/mnt/dev" /etc/fstab; then echo "/dev/sda1 /mnt/dev ext4 defaults 0 0" | sudo tee -a /etc/fstab fi

Link to this headingMount filesystem if does not already exist

if ! mountpoint -q "$DATA_DIR"; then mount -o discard,defaults,noatime "$VOLUME_NAME" "$DATA_DIR" fi

Link to this headingSet Strict mode to exit on failure

http://redsymbol.net/articles/unofficial-bash-strict-mode/